﻿// <copyright file="PieceBase.cs" company="ALCPU">
// Copyright (c) 2010 All Right Reserved
// </copyright>
// <author>Arthur Liberman</author>
// <email>Arthur_Liberman@hotmail.com</email>
// <date>03-31-2010</date>
// <summary>Contains basic piece definition.</summary>

namespace Chess.Figures
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows.Media;
    using ChessDefinitions;

    /// <summary>
    /// The base piece for all chess pieces
    /// </summary>
    public abstract class PieceBase : IPiece
    {
        /// <summary>
        /// Current player's piece color.
        /// </summary>
        private readonly IPieceColor color;

        /// <summary>
        /// The piece image.
        /// </summary>
        private Brush image;

        /// <summary>
        /// The gameboard.
        /// </summary>
        private Gameboard gameboard;

        /// <summary>
        /// Current position of this piece on the gameboard.
        /// </summary>
        private Position position;

        /// <summary>
        /// Initializes a new instance of the <see cref="PieceBase"/> class.
        /// </summary>
        /// <param name="color">The piece color.</param>
        /// <param name="gameboard">The gameboard.</param>
        /// <param name="position">The starting position.</param>
        public PieceBase(IPieceColor color, Gameboard gameboard, Position position)
        {
            this.color = color;
            this.gameboard = gameboard;
            this.position = position;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="PieceBase"/> class.
        /// </summary>
        /// <param name="piece">The piece.</param>
        public PieceBase(IPiece piece) : this(piece.Color, null, piece.Position)
        {
            if (piece is PieceBase)
            {
                this.GameEvent = (piece as PieceBase).GameEvent;
                this.gameboard = (piece as PieceBase).Gameboard;
            }
        }

        /// <summary>
        /// Prevents a default instance of the <see cref="PieceBase"/> class from being created.
        /// </summary>
        private PieceBase()
        {
        }

        /// <summary>
        /// Occurs when there is a game event.
        /// </summary>
        public event PieceEvent GameEvent;

        #region IFigure Members

        /// <summary>
        /// Gets the color of the piece.
        /// </summary>
        /// <value>The color.</value>
        public IPieceColor Color
        {
            get { return this.color; }
        }

        /// <summary>
        /// Gets or sets the object visually representing the piece in the game.
        /// </summary>
        /// <value>The representation object.</value>
        public virtual object RepresentationObject { get; set; }

        /// <summary>
        /// Gets the location of the piece.
        /// </summary>
        /// <value>The current location.</value>
        public Position Position
        {
            get { return new Position(this.position); }
        }

        /// <summary>
        /// Gets the move options.
        /// </summary>
        /// <value>An array of all possible moves.</value>
        public List<Position> MoveOptions
        {
            get { return this.GetMoveOptions(); }
        }

        /// <summary>
        /// Gets the attack options.
        /// </summary>
        /// <value>An array of all possible attacks.</value>
        public List<Position> AttackOptions
        {
            get { return this.GetAttackList(); }
        }

        /// <summary>
        /// Gets all possible move options.
        /// </summary>
        /// <value>All move options.</value>
        public List<Position> AllMoveOptions
        {
            get 
            {
                List<Position> posList = new List<Position>();
                posList.AddRange(this.MoveOptions);
                posList.AddRange(this.AttackOptions);
                return posList; 
            }
        }

        /// <summary>
        /// Gets or sets the image of the piece.
        /// </summary>
        /// <value>The image.</value>
        public Brush Image
        {
            get
            {
                return this.image;
            }

            set
            {
                this.RepresentationObject = value;
                this.image = value;
            }
        }

        /// <summary>
        /// Gets the gameboard.
        /// </summary>
        /// <value>The gameboard.</value>
        protected Gameboard Gameboard 
        {
            get { return this.gameboard; }
        }

        /// <summary>
        /// Moves the piece to the destination.
        /// </summary>
        /// <param name="destination">The destination.</param>
        /// <returns>
        ///     <c>true</c> if successful, <c>false</c> if not.
        /// </returns>
        public virtual bool MoveTo(Position destination)
        {
            return this.MoveTo(destination, false);
        }

        /// <summary>
        /// Attacks the specified target.
        /// </summary>
        /// <param name="target">The target.</param>
        /// <returns>
        ///     <c>true</c> if successful, <c>false</c> if not.
        /// </returns>
        public virtual bool Attack(Position target)
        {
            bool ret = false;

            if (this.AttackOptions.Contains(target))
            {
                this.Gameboard.Figures[target].Die(this);
                ret = this.MoveTo(target, true);
            }

            return ret;
        }

        /// <summary>
        /// Dies by the specified attacker.
        /// </summary>
        /// <param name="attacker">The attacker.</param>
        public virtual void Die(IPiece attacker)
        {
            this.NotifyOfGameEvent(attacker, GameEventType.Attack);
        }

        #endregion

        /// <summary>
        /// Moves the piece to the destination.
        /// </summary>
        /// <param name="destination">The destination.</param>
        /// <param name="ignoreMoveOptions">if set to <c>true</c> ignores move options.</param>
        /// <returns>
        ///     <c>true</c> if successful, <c>false</c> if not.
        /// </returns>
        protected virtual bool MoveTo(Position destination, bool ignoreMoveOptions)
        {
            bool ret = false;

            if (ignoreMoveOptions || this.MoveOptions.Contains(destination))
            {
                this.Gameboard.MovePiece(destination, this);
                this.position = destination;
                ret = true;
            }

            return ret;
        }

        /// <summary>
        /// Fills the move options.
        /// </summary>
        /// <returns>List of moves.</returns>
        protected abstract List<Position> GetMoveOptions();

        /// <summary>
        /// Fills the attack list.
        /// </summary>
        /// <returns>List of possible attacks.</returns>
        protected abstract List<Position> GetAttackList();

        /// <summary>
        /// Notifies the game of an event.
        /// </summary>
        /// <param name="cause">The cause of the event.</param>
        /// <param name="gameEventType">Type of the game event.</param>
        protected void NotifyOfGameEvent(IPiece cause, GameEventType gameEventType)
        {
            if (this.GameEvent != null)
            {
                GameEventArgs<IPiece> gameEventArgs = new GameEventArgs<IPiece>(cause, gameEventType);

                foreach (PieceEvent subscriber in this.GameEvent.GetInvocationList())
                {
                    try
                    {
                        subscriber(this, gameEventArgs);
                    }
                    catch (Exception)
                    {
                    }
                }
            }
        }
    }
}
